package com.su.utils;

import com.su.utils.ByteUtils;
import com.su.utils.ModBus;
import lombok.Getter;
import lombok.Setter;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Component
public class SocketForModBus {
    /** Socket Data Unit, SDU(host, port, ADU(address, PDU(functionCode, Data), Error Check)) */
    @Getter
    @Setter
    public static class SDU{
        private String host;

        @Override
        public String toString() {
            return "SDU{" +
                    "host='" + host + '\'' +
                    ", port=" + port +
                    ", adu=" + adu +
                    '}';
        }

        private int port;
        private ModBus.ADU adu;

        public SDU() {}
        public SDU(String host, int port) {
            this.host = host;
            this.port = port;
        }
    }

    @Transactional
    public List<Integer> perform(SDU sdu){
        Socket session = connect(sdu.getHost(), sdu.getPort());
        Objects.requireNonNull(session);
        sendMessage(session, sdu.getAdu());
        if (sdu.getAdu().getAddress().equals("00")){// 为广播发布，无应答（地址码为00）
            return null;
        } else {
            return receiveMessage(session);
        }
    }

    private Socket connect(String host, int port){
        Socket socket = new Socket();
        SocketAddress socketAddress = new InetSocketAddress(host, port);
        try {
            socket.connect(socketAddress, 2000); // 连不上的?毫秒断掉连接
            return socket;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
    private void sendMessage(Socket session, ModBus.ADU adu){
        String message = adu.toString();

        byte[] writeBytes = ByteUtils.hexStringToBytes(message);
        OutputStream os = null;
        try {
            os = session.getOutputStream();
            os.write(writeBytes);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private List<Integer> receiveMessage(Socket session){
        List<Integer> bytes = new ArrayList<>();
        DataInputStream dis;
        try {
            session.setSoTimeout(2000); // 设置socket读超时时间?毫秒
            dis = new DataInputStream(session.getInputStream());
        } catch (IOException e) {
            System.err.println("Get InputStream Failed");
            e.printStackTrace();
            return null;
        }
        try{
            int data;
            while ((data = dis.read()) != -1){
                bytes.add(data);
            }
        } catch (IOException e){
            if (e.getClass() != SocketTimeoutException.class){
                e.printStackTrace();
            }
        } finally{
            try {
                dis.close();
                session.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return bytes;
    }

}
